package org.offsync.util

sealed abstract class Duration {
  def nanoseconds: Long
  
  def milliseconds: Long = nanoseconds / 1000000

  def nanoPart: Int = (nanoseconds % 1000000).asInstanceOf[Int]
  
  def -(that: Duration): Duration
  
  def +(that: Duration): Duration
  
  def *(factor: Int): Duration
  
  def /(factor: Int): Duration
  
  def roundTo(interval: Duration): Duration
  
  def from(time: Time): Time
  
  def positiveTimeout: Long
  
  def sleep(): Unit
}

object Forever extends Duration {
  def nanoseconds: Long = Long.MaxValue

  def -(that: Duration): Duration = Forever
  
  def +(that: Duration): Duration = Forever
  
  def *(factor: Int): Duration = Forever
  
  def /(factor: Int): Duration = Forever
  
  def roundTo(interval: Duration): Duration = Forever

  def from(time: Time): Time = Never
  
  def positiveTimeout: Long = 0
  
  def sleep(): Unit = {
    val o = new Object
    o.synchronized {
      o.wait()
    }
  }
}

case class DurationNanos(val nanoseconds: Long) extends Duration {
  println("ns: " + nanoseconds)
  def -(that: Duration): Duration = DurationNanos(nanoseconds - that.nanoseconds)

  def +(that: Duration): Duration = DurationNanos(nanoseconds + that.nanoseconds)
  
  def *(factor: Int): Duration = DurationNanos(nanoseconds * factor)
  
  def /(factor: Int): Duration = DurationNanos(nanoseconds / factor)
  
  def roundTo(interval: Duration): Duration = {
    val i = interval.nanoseconds
    DurationNanos((nanoseconds + (i / 2)) / i * i)
  }

  def from(time: Time): Time = {
    if (time == Never) return Never
    if (nanoseconds >= 0) {
      val newTimeNanos = time.nanoseconds + nanoseconds
      if (newTimeNanos < time.nanoseconds) {
        return Never
      }
      return TimeNanos(newTimeNanos)
    } else {
      val newTimeNanos = time.nanoseconds + nanoseconds
      if (newTimeNanos > time.nanoseconds) {
        return Time.minValue
      }
      return TimeNanos(newTimeNanos)
    }
  }
  
  def positiveTimeout: Long = nanoseconds

  def sleep(): Unit = {
    println(milliseconds)
    println(nanoPart)
    Thread.sleep(milliseconds, nanoPart)
  }
}
